package dk.itu.samd.group2.tagapastry.messages;

import java.io.IOException;

import rice.p2p.commonapi.Endpoint;
import rice.p2p.commonapi.Id;
import rice.p2p.commonapi.NodeHandle;
import rice.p2p.commonapi.rawserialization.InputBuffer;
import rice.p2p.commonapi.rawserialization.OutputBuffer;
import dk.itu.samd.group2.tagapastry.Index;
import dk.itu.samd.group2.tagapastry.IndexImpl;
import dk.itu.samd.group2.tagapastry.IndexRelative;
import dk.itu.samd.group2.tagapastry.Tag;
import dk.itu.samd.group2.tagapastry.TagFactory;
import dk.itu.samd.group2.tagapastry.TagapastryImpl;
import dk.itu.samd.group2.tagapastry.messages.forwardStrategies.SinglecastReturnToParentStrategy;
import dk.itu.samd.group2.tagapastry.util.TitleGenerator;

public class TagMsg extends IndexMsg {

	public static final short TYPE = 1;
	private static final long serialVersionUID = TYPE;

	// Should be object class
	private String object = null;
	private String hash;

	public TagMsg(Tag tag, NodeHandle originalSender, String object) {
		super(tag, originalSender);
		this.object = object;
		
		// Why don't we take hash from tag keyword ? 
		// For some reason object is different from the tag itself
		// So hash should be based on object
		TitleGenerator tg = new TitleGenerator();
		this.hash = tg.generateTitle(object);
		forwardStrategy = new SinglecastReturnToParentStrategy(hash);
	}

	public TagMsg(InputBuffer buf, Endpoint endpoint) throws IOException {
		super(buf, endpoint);
		this.object = buf.readUTF();
		this.hash = buf.readUTF();
		forwardStrategy = new SinglecastReturnToParentStrategy(hash);
	}
	
	public int getSize() {
		int size = super.getSize();
		return size + object.length() + hash.length();
	}

	@Override
	public void execute(TagapastryImpl taga) {		
		Index index = taga.getIndex(tag);
		if (index == null) {
			index = new IndexImpl(tag, taga);
			index.insert(object, hash);
			if (this.hasParent()) {
				confirmCreationToParent(taga);
			}
			return;
		} 
		if (index.bufferOrForward(this)) {
			return;
		}

		index.insert(object, hash);
	}

	@Override
	public short getType() {
		return TYPE;
	}

	@Override
	public void serialize(OutputBuffer buf) throws IOException {
		super.serialize(buf);
		buf.writeUTF(object);
		buf.writeUTF(hash);
	}

	@Override
	public String toString() {
		String str = super.toString();
		str += ", object : " + object + ", hash: " + hash + " }";
		return str;
	}

	@Override
	public Id getRecepientId() {
		return tag.getId();
	}

	@Override
	public boolean indexCreator() {
		return true;
	}

	@Override
	public IndexMsg cloneForChild(IndexRelative child) {
		IndexMsg newMsg = new TagMsg(child.getTag(), originalSender, object);
		return newMsg;
	}
	
	private boolean hasParent() {
		return !tag.getExtension().isEmpty();
	}
	
	private void confirmCreationToParent(TagapastryImpl taga) {
		Tag parentTag =  TagFactory.duplicateTagMinusExtension(tag);
		char childExtension = tag.getExtension().charAt(tag.getExtension().length() - 1);
		IndexExpansionConfirmationMsg msg = new IndexExpansionConfirmationMsg(parentTag, taga.getNodeHandle(), true, childExtension);
		taga.send(msg);
	}

}
